home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / PROGNG_C / TPTC17GS.LZH / TPCUNIT.INC < prev    next >
Text File  |  1988-04-12  |  15KB  |  723 lines

  1.  
  2. (*
  3.  * TPTC - Turbo Pascal to C translator
  4.  *
  5.  * (C) 1988 Samuel H. Smith (rev. 13-Feb-88)
  6.  *
  7.  *)
  8.  
  9. (********************************************************************)
  10. (*
  11.  * process interface, implementation and uses statements
  12.  *
  13.  *)
  14.  
  15. (********************************************************************)
  16. procedure punit;
  17.    {parse a unit clause}
  18. begin
  19.    if debug_parse then write(' <unit>');
  20.  
  21.    in_unit := true;
  22.    gettok;     {consume the UNIT}
  23.  
  24.    unitproc := ltok + '_init';
  25.    puts('/* Unit '+ltok+' */ ');
  26.  
  27.    gettok;     {consume the unit name}
  28.    usesemi;
  29. end;
  30.  
  31.  
  32. (********************************************************************)
  33. procedure puses;
  34.    {parse a uses clause}
  35. begin
  36.    if debug_parse then write(' <uses>');
  37.  
  38.    gettok;     {consume the USES}
  39.    
  40.    repeat
  41.       {load the saved unit header symbol table, generate .UNH include}
  42.       load_unitfile(ltok,globals);
  43.  
  44.       {move interface section to skip new entries}
  45.       top_interface := globals;     
  46.       
  47.       gettok;                       {consume the unit name}
  48.       if tok[1] = ',' then
  49.          gettok;
  50.    until (tok[1] = ';') or recovery;
  51.    
  52. end;
  53.  
  54.  
  55. (********************************************************************)
  56. procedure pinterface;
  57. begin
  58.    if debug_parse then write(' <interface>');
  59.    gettok;
  60.       
  61.    in_interface := true;
  62.    top_interface := globals;
  63.  
  64.    putline;
  65.    putln('#define IN_'+unitname+'  /* globals defined here */');
  66.    putln('#include <'+unitname+'.UNH>');
  67.    
  68.    inc(unitlevel);
  69.    assign(ofd[unitlevel],unitname+'.UNH');
  70.    rewrite(ofd[unitlevel]);
  71.    getmem(outbuf[unitlevel],inbufsiz);
  72.    SetTextBuf(ofd[unitlevel],outbuf[unitlevel]^,inbufsiz);
  73.  
  74.    putline;
  75.    putln('/* Unit header for: '+outname+' -- Made by '+version1+' */');
  76.    putline;
  77.    putln('#ifndef '+unitname+'_LOADED  /* prevent multiple loading */');
  78.    putln('#define '+unitname+'_LOADED');
  79.    putline;
  80.  
  81.    (* .UNH includes will be generated here *)
  82.    if tok = 'USES' then
  83.       puses;
  84.  
  85.    putline;
  86.    putln('#ifdef IN_'+unitname+'  /* define globals here? */');
  87.    putln('#define extern');
  88.    putln('#endif');
  89.  
  90.    usesemi;
  91. end;
  92.  
  93.  
  94. (********************************************************************)
  95. procedure pimplementation;
  96. begin
  97.    if debug_parse then write(' <implementation>');
  98.  
  99.    if not in_interface then
  100.       exit;
  101.  
  102.    {terminate the .unh file being generated}
  103.    putline;
  104.    puts('extern void  '+unitproc);
  105.    if unitheader then
  106.       putln('(void);')
  107.    else
  108.       putln('(int argc, char **argv);');
  109.    putln('#undef extern');
  110.    putln('#endif');
  111.  
  112.    close(ofd[unitlevel]);
  113.    freemem(outbuf[unitlevel],inbufsiz);
  114.    dec(unitlevel);
  115.    
  116.    {create the requested unit symbol file}
  117.    newsym(unitproc, ss_unit, 2, 0, 0, 0, voidsym);
  118.    create_unitfile(unitname+'.UNS',globals,top_interface);
  119.    in_interface := false;
  120.  
  121.    gettok;
  122. end;
  123.  
  124.  
  125.    
  126. (********************************************************************)
  127. (*
  128.  * process generic declaration section
  129.  *   dispatches to const, type, var, proc, func
  130.  *   enter with tok=section type
  131.  *   exit with tok=next section type
  132.  *
  133.  *)
  134.  
  135. procedure psection;
  136. begin
  137.    if recovery then
  138.    begin
  139.       while toktype <> keyword do
  140.          gettok;
  141.       recovery := false;
  142.    end;
  143.  
  144.    if debug_parse then write(' <section>');
  145.  
  146.    if tok = 'UNIT' then
  147.       punit
  148.    else
  149.    
  150.    if tok = 'INTERFACE' then
  151.       pinterface
  152.    else
  153.    
  154.    if tok = 'IMPLEMENTATION' then
  155.       pimplementation
  156.    else
  157.    
  158.    if tok = 'USES' then
  159.    begin
  160.       puses;
  161.       usesemi;
  162.    end
  163.    else
  164.    
  165.    if (tok = 'EXTERNAL')  or (tok = 'OVERLAY') or
  166.       (tok = 'PROCEDURE') or (tok = 'FUNCTION') then
  167.       progunit
  168.    else
  169.  
  170.    if tok = 'CONST' then
  171.       pconst
  172.    else
  173.  
  174.    if tok = 'TYPE' then
  175.       ptype
  176.    else
  177.  
  178.    if tok = 'VAR' then
  179.       pvar
  180.    else
  181.  
  182.    if tok = 'LABEL' then
  183.       plabel
  184.    else
  185.  
  186.    if tok[1] = '{' then
  187.       pblock
  188.    else
  189.  
  190.    if (tok[1] = '.') or (tok[1] = '}') then
  191.    begin
  192.       tok := '.';
  193.       exit;
  194.    end
  195.    else
  196.       syntax('Section header expected (psection)');
  197. end;
  198.  
  199.  
  200. (********************************************************************)
  201. (*
  202.  * process argument declarations to
  203.  *    program, procedure, function
  204.  *
  205.  * enter with header as tok
  206.  * exits with tok as ; or :
  207.  *
  208.  *)
  209.  
  210. const
  211.    extern = true;
  212.    
  213. procedure punitheader(is_external: boolean);
  214. var
  215.    proc:    string40;
  216.    proclit: string40;
  217.    vars:    paramlist;
  218.    types:   paramlist;
  219.    i:       integer;
  220.    ii:      integer;
  221.    rtype:   string40;
  222.    rsym:    symptr;
  223.    varval:  integer;
  224.    varon:   boolean;
  225.    locvar:  integer;
  226.    iptr:    integer;
  227.  
  228. begin
  229.    gettok;                 {skip unit type}
  230.    proclit := ltok;
  231.  
  232.    if (unitlevel > 1) and (not in_interface) then
  233.    begin
  234.       {make name unique if it clashes with an existing global}
  235.       if cursym = nil then
  236.          proc := proclit
  237.       else
  238.          proc := procnum + '_' + proclit;
  239.          
  240.       warning('Nested function');
  241.       
  242.       writeln(ofd[unitlevel-1],^M^J'   /* Nested function: ',proc,' */ ');
  243.       inc(objtotal,2);
  244.    end
  245.    else
  246.       proc := proclit;
  247.  
  248.    gettok;                 {skip unit identifier}
  249.  
  250.    vars.n := 0;
  251.    varval := 0;       { 0 bit means value, 1 = var }
  252.    varon  := false;
  253.  
  254.    (* process param list, if any *)
  255.    if tok[1] = '(' then
  256.    begin
  257.       gettok;
  258.  
  259.       while (tok[1] <> ')') and not recovery do
  260.       begin
  261.  
  262.          ii := vars.n + 1;
  263.          repeat
  264.             if tok[1] = ',' then
  265.                gettok;
  266.  
  267.             if tok = 'VAR' then
  268.             begin
  269.                gettok;
  270.                varon := true;
  271.             end;
  272.  
  273.             inc(vars.n);
  274.             if vars.n > maxparam then
  275.                fatal('Too many params (punitheader)');
  276.  
  277.             vars.id[vars.n] := ltok;
  278.             gettok;
  279.  
  280.          until tok[1] <> ',';
  281.  
  282.          if tok[1] = ':' then       
  283.          begin
  284.             gettok;   {consume the :}
  285.    
  286.             {parse the param type}
  287.             rtype := psimpletype;
  288.             rsym := curparent;
  289.          end
  290.          else
  291.  
  292.          begin    {untyped variable if ':' is missing}
  293.             rtype := 'void';
  294.             rsym := voidsym;
  295.          end;
  296.  
  297.          {assign and param types, converting 'var' and 'array' params}
  298.          if rtype[1] = '^' then
  299.             rtype[1] := '*';
  300.  
  301.          {flag var parameters; strings and arrays are implicitly var in C}
  302.          iptr := 0;
  303.          if rsym^.symtype = ss_array then
  304.             rtype := rsym^.parent^.repid + ' *'
  305.          else
  306.          if varon then
  307.             iptr := 1 shl (ii - 1);
  308.  
  309.          {assign data types for each ident}
  310.          for i := ii to vars.n do   
  311.          begin
  312.             types.id[i] := rtype;
  313.             types.sym[i] := rsym;
  314.             varval := varval or iptr;
  315.             iptr := iptr shl 1;
  316.          end;
  317.  
  318.          if tok[1] = ';' then
  319.          begin
  320.             gettok;
  321.             varon := false;
  322.          end;
  323.  
  324.       end;   {) seen}
  325.  
  326.       gettok;   {consume the )}
  327.    end;
  328.  
  329.    (* process function return type, if any *)
  330.    if tok[1] = ':' then
  331.    begin
  332.       gettok;            {consume the :}
  333.       rtype := psimpletype;
  334.       rsym := curparent;
  335.       
  336.       if rsym^.symtype = ss_array then
  337.          rtype := rsym^.parent^.repid + ' *';
  338.  
  339. (* writeln('return rtype=',rtype); *)
  340.    end
  341.    else
  342.  
  343.    begin
  344.       rtype := 'void';
  345.       rsym := voidsym;
  346.    end;
  347.  
  348.    putline;
  349.    
  350.    (* prefix procedure decl's when external *)
  351.    if is_external then
  352.    begin
  353.       putln(ljust('extern '+rtype,identlen)+proc+'();');
  354.       addsym(globals,proc,ss_func,0,varval,0,0,cexprsym,false);
  355.       exit;
  356.    end;
  357.  
  358.  
  359.    (* process 'as NEWNAME' clause, if present (tptc extention to specify
  360.       the replacement name in the symbol table *)
  361.    if tok = 'AS' then
  362.    begin
  363.       gettok;
  364.       proc := usetok;
  365.    end;
  366.     
  367.  
  368.    (* output the return type, proc name, formal param list *)
  369.    if in_interface then
  370.       rtype := 'extern '+rtype;
  371.    puts(ljust(rtype,identlen)+proc+'(');
  372.  
  373.    if vars.n = 0 then
  374.       puts('void');
  375.  
  376.  
  377.    (* output the formal param declarations *)
  378.    locvar := varval;
  379.    for i := 1 to vars.n do
  380.    begin
  381.       iptr := -1;
  382.  
  383.       if (locvar and 1) = 1 then
  384.       begin
  385.          iptr := -2;
  386.          types.id[i] := types.id[i] + ' *';
  387.       end;
  388.  
  389.       puts(ljust(types.id[i],identlen)+vars.id[i]);
  390.       addsym(locals,vars.id[i],ss_scalar,iptr,0,0,
  391.                     types.sym[i]^.base,types.sym[i],true);
  392.       locvar := locvar shr 1;
  393.  
  394.       if i < vars.n then
  395.       begin
  396.          putln(','); 
  397.          puts(ljust('',identlen+length(proc)+1));
  398.       end;
  399.    end;
  400.  
  401.    puts(')');
  402.    nospace := false;
  403.  
  404.    {enter the procedure in the global symbol table}
  405.    addsym(globals,proclit,ss_func,vars.n,varval,0,0,rsym,false);
  406.    cursym^.repid := proc;
  407. end;
  408.  
  409.  
  410. (********************************************************************)
  411. (*
  412.  * process body of program unit
  413.  *   handles all declaration sections
  414.  *   and a single begin...end
  415.  *   recursively handles procedure declarations
  416.  *   ends with tok=}
  417.  *)
  418.  
  419. procedure punitbody;
  420. begin
  421.    gettok;
  422.  
  423.    if tok = 'INTERRUPT' then
  424.    begin
  425.       gettok;
  426.       warning('Interrupt handler');
  427.    end;
  428.    
  429.    if tok = 'FORWARD' then
  430.    begin
  431.       puts(';');
  432.       gettok;
  433.    end
  434.    else
  435.  
  436.    if tok = 'EXTERNAL' then
  437.    begin
  438.       puts('/* ');
  439.       repeat
  440.          puttok;
  441.          gettok;
  442.       until tok[1] = ';';
  443.       puts(' */ ;');
  444.    end
  445.    else
  446.  
  447.    if tok = 'INLINE' then
  448.    begin
  449.       newline;
  450.       putln('{');
  451.       puts('   ');
  452.       pinline;
  453.       putln('}');
  454.    end
  455.    else
  456.  
  457.    begin
  458.       puts('{ ');
  459.  
  460.       repeat
  461.          psemi;
  462.          if tok[1] <> '{' then
  463.             psection;
  464.       until tok[1] = '{';
  465.  
  466.       gettok;                 {get first token of first statement}
  467.  
  468.       while (tok[1] <> '}') and not recovery do
  469.       begin
  470.          pstatement;             {process the statement}
  471.          psemi;
  472.       end;
  473.  
  474.       puttok;
  475.    end;
  476. end;
  477.  
  478.  
  479. (********************************************************************)
  480. procedure enter_procdef;
  481.    {increase output file level and direct output to the new file}
  482. var
  483.    nam:  anystring;
  484. begin
  485.    {increment this procedure number}
  486.    inc(procnum[2]);
  487.    if procnum[2] > 'Z' then
  488.    begin
  489.       inc(procnum[1]);
  490.       procnum[2] := 'A';
  491.    end;
  492.  
  493.    inc(unitlevel);
  494.    if unitlevel > maxnest then
  495.       fatal('Functions nested too deeply');
  496.  
  497.    str(unitlevel,nam);
  498.    nam := workdir + nestfile + nam;
  499.  
  500.    assign(ofd[unitlevel],nam);
  501.    {$i-} rewrite(ofd[unitlevel]); {$i+}
  502.  
  503.    if ioresult <> 0 then
  504.    begin
  505.       dec(unitlevel);
  506.       ltok := nam;
  507.       fatal('Can''t create tempfile');
  508.    end;
  509.  
  510.    if maxavail-300 <= inbufsiz then
  511.    begin
  512.       ltok := nam;
  513.       fatal('Out of memory');
  514.    end;
  515.  
  516.    getmem(outbuf[unitlevel],inbufsiz);
  517.    SetTextBuf(ofd[unitlevel],outbuf[unitlevel]^,inbufsiz);
  518. end;
  519.  
  520.  
  521. (********************************************************************)
  522. procedure exit_procdef;
  523.    {copy the outer output file to the next lower level output
  524.     and reduce output level by 1}
  525. var
  526.    line:  string;
  527.  
  528. begin
  529.    if unitlevel < 1 then 
  530.       exit;
  531.    
  532.    close(ofd[unitlevel]);
  533.    reset(ofd[unitlevel]);
  534.    SetTextBuf(ofd[unitlevel],outbuf[unitlevel]^,inbufsiz);
  535.  
  536.    while not eof(ofd[unitlevel]) do
  537.    begin
  538.       readln(ofd[unitlevel],line);
  539.       writeln(ofd[0],line);
  540.    end;
  541.  
  542.    close(ofd[unitlevel]);
  543.    erase(ofd[unitlevel]);
  544.    freemem(outbuf[unitlevel],inbufsiz);
  545.    dec(unitlevel);
  546. end;
  547.  
  548.  
  549. (********************************************************************)
  550. (*
  551.  * process program, procedure and function declaration
  552.  *
  553.  * enter with tok=function
  554.  * exit with tok=;
  555.  *
  556.  *)
  557.  
  558. procedure progunit;
  559. var
  560.    top: symptr;
  561. begin
  562.    if debug_parse then write(' <unit>');
  563.  
  564.    nospace := true;
  565.    top := locals;
  566.  
  567.    if (tok = 'OVERLAY') then
  568.       gettok;
  569.  
  570.    if (tok = 'EXTERNAL') then  {mt+}
  571.    begin
  572.       gettok;      {consume the EXTERNAL}
  573.  
  574.       if tok[1] = '[' then
  575.       begin
  576.          gettok;   {consume the '['}
  577.  
  578.          puts('/* overlay '+ltok+' */ ');
  579.          gettok;   {consume the overlay number}
  580.  
  581.          gettok;   {consume the ']'}
  582.       end;
  583.  
  584.       punitheader(extern);
  585.       usesemi;
  586.       purgetable(locals,top);
  587.    end
  588.    else
  589.  
  590.    if in_interface then
  591.    begin
  592.       nospace := false;
  593.       punitheader(not extern);
  594.  
  595.       puts(';');
  596.       usesemi;
  597.       
  598.       if tok = 'INLINE' then
  599.       begin
  600.          pinline;
  601.          warning('Inline procedure');
  602.       end;
  603.  
  604.       purgetable(locals,top);
  605.    end
  606.    else
  607.    
  608.    begin
  609.       {enter a (possibly nested) procedure}
  610.       enter_procdef;
  611.  
  612.       punitheader(not extern);
  613.       punitbody;
  614.       gettok;
  615.       usesemi;
  616.       purgetable(locals,top);
  617.  
  618.       {exit the (possibly nested) procedure, append text to toplevel outfile}
  619.       exit_procdef;
  620.    end;
  621.  
  622. end;
  623.  
  624.  
  625.  
  626. (********************************************************************)
  627. (*
  628.  * process main program
  629.  *
  630.  *  expects program head
  631.  *  optional declarations
  632.  *  block of main code
  633.  *  .
  634.  *
  635.  *)
  636.  
  637. procedure pmain;
  638.    {process unit initializer block (or top-level main), if any}
  639. var
  640.    un: integer;
  641.  
  642. begin
  643.    putline;
  644.  
  645.    if in_unit then
  646.    begin
  647.       if unitheader then
  648.          putln('void '+unitproc+'()')
  649.       else
  650.          putln('void tptcsys_init(int argc, char **argv)');
  651.  
  652.       putln('{');
  653.       putln('   static char unit_initialized = 0;');
  654.       putln('   if (unit_initialized) return;');
  655.       putline;
  656.       putln('   unit_initialized = 1;');
  657.    end
  658.    else
  659.  
  660.    begin
  661.       putln('void main(int argc, char **argv)');
  662.       putln('{');
  663.       putln('   tptcsys_init(argc,argv);');
  664.    end;
  665.  
  666.    if unitheader then
  667.       un := 2
  668.    else
  669.       un := 1;
  670.  
  671.    while un <= init_count do
  672.    begin
  673.       putln('   '+init_tab[un]+';');
  674.       inc(un);
  675.    end;
  676.    newline;
  677.  
  678.    if tok[1] = '{' then
  679.       gettok;                 {get first token of main block}
  680.  
  681.    while (tok[1] <> '}') and (tok[1] <> '.') do
  682.    begin
  683.       pstatement;                {process the statement}
  684.       psemi;
  685.    end;
  686.  
  687.    putln('}');
  688.    putline;
  689. end;
  690.  
  691.  
  692. procedure pprogram;
  693. begin
  694.    getchar;  {get first char}
  695.    gettok;   {get first token}
  696.  
  697.    if (tok = 'PROGRAM') then
  698.    begin
  699.       comment_statement;
  700.       gettok;
  701.    end;
  702.  
  703.    if tok = 'MODULE' then
  704.    begin
  705.       mt_plus := true;   {shift into pascal/mt+ mode}
  706.       comment_statement;
  707.       gettok;
  708.    end;
  709.  
  710.    repeat
  711.       psemi;
  712.       if tok = 'MODEND' then
  713.          exit;
  714.  
  715.       if (tok[1] <> '{') then
  716.          psection;
  717.    until (tok[1] = '{') or (tok[1] = '.') or recovery;
  718.  
  719.    {process the main block, if any}
  720.    pmain;
  721. end;
  722.  
  723.